
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.*;
import java.util.ArrayList;
import javax.swing.Timer;


import javax.swing.JPanel;

public class ImagePanel extends JPanel {

	private static final long serialVersionUID = 1L;
	private Image img;
	private int currColor, size;
	final private Color[] colors = {Color.WHITE, Color.RED, Color.GREEN,
		Color.BLUE, Color.BLACK, Color.YELLOW, Color.CYAN};
	private ArrayList<ImagePoint> pictureArray;
	private int curPoint;
	private Timer timer;
	private boolean drawing;

	/**
	 * Constructor for Image Panel
	 *
	 * @param image Image to be added
	 */
	public ImagePanel(Image image) {
		img = image;
		size = 5;
		currColor = 1;
		drawing = true;
		setPreferredSize(new Dimension(img.getxSize(), img.getySize()));
		MouseDevice listener = new MouseDevice();
		addMouseListener(listener);
		addMouseMotionListener(listener);
	}

	// STUB Testing purposes only.
	public int getBrushSize() {
		return size;
	}

	public int getBrushColor() {
		return colors[currColor].getRGB();
	}
	// STUB

	/**
	 *
	 */
	public void paintComponent(Graphics p) {
		super.paintComponent(p);
		int origColor = currColor;
		p.setColor(colors[img.getBackgroundColor()]);
		p.fillRect(0, 0, img.getxSize(), img.getySize());
		ArrayList<Point> keys = img.getKeys();
		Point lastKey = null;
		for (int i = 0; i < keys.size(); i++) {
			if (lastKey != null) {
				int x = keys.get(i).x;
				int y = keys.get(i).y;
				if (x <= img.getxSize() && y <= img.getySize()) {
					currColor = img.getColorsAtPos(x, y);
					size = img.getSizeAtPos(x, y);
					p.setColor(colors[currColor]);
					p.fillOval(x, y, size, size);
				} else {
					img.remove(keys.get(i));
				}
			}
			lastKey = keys.get(i);
		}
		setCurrColor(origColor);
	}

	/**
	 * Changes the background color and repaints
	 *
	 * @param color Color index to be changed
	 */
	public void setBackgroundColor(int color) {
		img.setBackgroundColor(color);
		repaint();
	}

	/**
	 * Clears the entire Image
	 */
	public void clearImage() {
		if (timer != null) {
			timer.stop();
		}
		
		img.clearColoredPoints();
		img.setBackgroundColor(0);
		repaint();
	}

	/**
	 * Updates the current color
	 *
	 * @param i New color index
	 */
	public void setCurrColor(int i) {
		currColor = i;
	}

	/**
	 * Changes the Image
	 *
	 * @param image New Image
	 */
	public void setImage(Image image) {
		img = image;
	}

	/**
	 * Changes the current size of the Image and repaints
	 *
	 * @param i New size
	 */
	public void changeSize(int i, int j) {
		img.setySize(i);
		img.setxSize(j);
		repaint();
	}

	/**
	 * Sets the size of the brush to a square with sides of size i
	 *
	 * @param i Edge size
	 */
	public void setPaintSize(int i) {
		size = i;
	}

	/**
	 * Rotates Image and repaints
	 *
	 * public void rotateImage() { img.rotate(); repaint(); }
        *
	 */
	/**
	 *
	 * @return The Image of the Panel
	 */
	public Image getImage() {
		return img;
	}

	/**
	 * Sets whether drawing by the user is activated or not 
        *
	 */
	public void setDrawing(boolean drawing) {
		this.drawing = drawing;
	}

	/**
	 * Draws an image  
        *
	 */
	public void drawImage(ArrayList<ImagePoint> picture) {
		DrawerTaskListener drawerTask = new DrawerTaskListener(picture, this);

		this.timer = new Timer(150, drawerTask);
		this.timer.setRepeats(true);
		this.timer.start();
	}

	/**
	 * Mouse Listener and Mouse Motion Listener for Panel
	 *
	 * @author Andrew Oberlin
	 *
	 */
	private class MouseDevice implements MouseListener, MouseMotionListener {

		public void mousePressed(MouseEvent event) {
		}

		/**
		 * If the cursor is normal, changes an Image by drawing. If it is not, it will change the
		 * size of the Image
		 */
		public void mouseDragged(MouseEvent event) {
			if (drawing) {
				if (getCursor().getType() == Cursor.DEFAULT_CURSOR) {
					mouseClicked(event);
				} else {
					img.setxSize((int) event.getPoint().x);
					img.setySize((int) event.getPoint().y);
					repaint();
				}
			}
		}

		/**
		 * Changes the points that are colored
		 */
		public void mouseClicked(MouseEvent event) {
			if (drawing) {
				Point pt = event.getPoint();
				if (pt.x <= img.getxSize() && pt.y <= img.getySize()) {
					/*
					 * for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { int x =
					 * pt.x + i; int y = pt.y + j; img.add(new Point(x,y), currColor); }
				}
					 */
					img.add(new Point(pt.x, pt.y), currColor, size);
					repaint();
				}
			}
		}

		public void mouseReleased(MouseEvent event) {
		}

		public void mouseEntered(MouseEvent event) {
		}

		public void mouseExited(MouseEvent event) {
		}

		/**
		 * Checks to see if the mouse is in the bottom right corner of the image to change its size
		 */
		public void mouseMoved(MouseEvent event) {
			if (isInBox(event.getPoint())) {
				setCursor(new Cursor(Cursor.SE_RESIZE_CURSOR));
			} else {
				setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
			}
		}

		/**
		 * Finds whether the point is in the bottom right corner
		 *
		 * @param p Point to be analyzed
		 * @return Boolean indicating whether or not the point is in the box
		 */
		private boolean isInBox(Point p) {
			boolean inBox = false;
			if (p.x > img.getxSize() && p.x < img.getxSize() + 10) {
				inBox = true;
			} else {
				inBox = false;
			}
			if (p.y > img.getySize() && p.y < img.getySize() + 10 && inBox) {
				inBox = true;
			} else {
				inBox = false;
			}
			return inBox;
		}
	}

	private class DrawerTaskListener implements ActionListener {

		private ArrayList<ImagePoint> picture;
		private ImagePanel imagePanel;
		private int curPoint;

		public DrawerTaskListener(ArrayList<ImagePoint> picture, ImagePanel imagePanel) {
			this.picture = picture;
			this.imagePanel = imagePanel;
			this.curPoint = 0;
		}

		public void actionPerformed(ActionEvent evt) {
			ImagePoint point = picture.get(curPoint);
			imagePanel.img.add(point.getPoint(), point.getColor(), point.getSize());
			imagePanel.repaint();
			curPoint++;
			if (curPoint >= picture.size()) {
				imagePanel.timer.stop();
			}
		}
	}
}